/**
 * Posicion.cpp
 *
 *  Created on: 27/12/2009
 *      Author: San Martín, Matías I.
 */

#include "Posicion.h"

#include  <cmath>

#include "../../Framework/Common/File.h"

//asigna la posición 0,0
Posicion::Posicion()
{
	_coordenadas.first = 0;
	_coordenadas.second = 0;
	this->setTamanio(sizeof(t_coordenada) * 2);
}

Posicion::Posicion(t_coordenada x, t_coordenada y)
{
	_coordenadas.first = x;
	_coordenadas.second = y;
	this->setTamanio(sizeof(t_coordenada) * 2);
}

Posicion::~Posicion()
{
}


std::ostream &operator<<( std::ostream &stream, const Posicion &obj )
{
  return stream << "Posicion(" << obj._coordenadas.first <<
				  "," << obj._coordenadas.second << ")";
}

void Posicion::setXY(t_coordenada x, t_coordenada y)
{
	_coordenadas.first = x;
	_coordenadas.second = y;
}

t_coordenada Posicion::getX() const
{
	return _coordenadas.first;
}

t_coordenada Posicion::getY() const
{
	return _coordenadas.second;
}

void Posicion::normalizar()
{
	double modulo = this->getModulo();
	_coordenadas.first /= modulo;
	_coordenadas.second /= modulo;
}

double Posicion::getModulo() const
{
	return sqrt(_coordenadas.first * _coordenadas.first +
			_coordenadas.second * _coordenadas.second);
}

T_DISTANCIA Posicion::getDistancia(const Posicion& otro) const
{
	t_coordenada diffX = _coordenadas.first - otro._coordenadas.first;
	t_coordenada diffY = _coordenadas.second - otro._coordenadas.second;
	return sqrt(diffX * diffX + diffY * diffY);
}

Posicion Posicion::getDireccion(const Posicion& destino, double multiplicador) const
{
	Posicion diferencia = destino - *this;
	double modulo = diferencia.getModulo();
	Posicion resultado
			(
					diferencia.getX() * multiplicador / modulo,
					diferencia.getY() * multiplicador / modulo
			);
	return  resultado;
}

bool Posicion::operator == (const Posicion& otro) const
{
	return _coordenadas.first == otro._coordenadas.first &&
			_coordenadas.second == otro._coordenadas.second;
}

Posicion& Posicion::operator += (const Posicion& sumar)
{
	return *this = *this + sumar;
}

Posicion Posicion::operator - (const Posicion& restar) const
{
	Posicion resultado;
	resultado._coordenadas.first = _coordenadas.first - restar._coordenadas.first;
	resultado._coordenadas.second = _coordenadas.second - restar._coordenadas.second;
	return resultado;
}

Posicion Posicion::operator + (const Posicion& sumar) const
{
	Posicion resultado;
	resultado._coordenadas.first = _coordenadas.first + sumar._coordenadas.first;
	resultado._coordenadas.second = _coordenadas.second + sumar._coordenadas.second;
	return resultado;
}

Posicion Posicion::operator / (double divisor) const
{
	Posicion resultado;
	resultado._coordenadas.first = _coordenadas.first / divisor;
	resultado._coordenadas.second = _coordenadas.second  / divisor;
	return resultado;
}

Posicion Posicion::operator * (double factor) const
{
	Posicion resultado;
	resultado._coordenadas.first = _coordenadas.first * factor;
	resultado._coordenadas.second = _coordenadas.second  * factor;
	return resultado;
}

size_t Posicion::save (int fd) const
{
	size_t guardar = 0;

	guardar += sizeof(_coordenadas.first) * 2;
	File::writeAll(fd,&_coordenadas.first,sizeof(_coordenadas.first));

	File::writeAll(fd,&_coordenadas.second,sizeof(_coordenadas.second));

	return guardar;
}

size_t Posicion::load (int fd)
{
	size_t cargar = 0;

	cargar += sizeof(_coordenadas.first) * 2;
	File::readAll(fd,&_coordenadas.first,sizeof(_coordenadas.first));

	File::readAll(fd,&_coordenadas.second,sizeof(_coordenadas.second));

	this->setTamanio(cargar);
	return cargar;
}

/**
 * @see middleware::io::SerializableToArray#saveToArray(int)
 */
size_t Posicion::saveToArray (uint8_t* arr) const {
	uint8_t* arr_original = arr;

	memcpy(arr, &_coordenadas.first, sizeof(_coordenadas.first));
	arr += sizeof(_coordenadas.first);

	memcpy(arr, &_coordenadas.second, sizeof(_coordenadas.second));
	arr += sizeof(_coordenadas.second);

	return arr - arr_original;
}

/**
 * @see middleware::io::SerializableToArray#loadFromArray(int)
 */
size_t Posicion::loadFromArray (const uint8_t* arr) {
	const uint8_t* arr_original = arr;

	memcpy(&_coordenadas.first, arr, sizeof(_coordenadas.first));
	arr += sizeof(_coordenadas.first);

	memcpy(&_coordenadas.second, arr, sizeof(_coordenadas.second));
	arr += sizeof(_coordenadas.second);

	size_t cargar = arr - arr_original;
	this->setTamanio(cargar);

	return cargar;
}
